#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tokens.h>
#include <parser.h>

#define MEMSIZE 0x100000
int nextentry = 0;
char symbol[MEMSIZE][32];
double memory[MEMSIZE];

double stack[MEMSIZE];
int sp = -1;

void push(double val)
{
	if (sp < MEMSIZE) {
	    stack[++sp] = val;
	} else {
	    fprintf(stderr, "memory room space exceeded... exiting\n");
	    exit(-5);
	}
}

double pop(void)
{
    return stack[sp--];
}


lookup(char key[])
{
    int i;
    for (i = 0; i < nextentry; i++) {
	if (strcmp(key, symbol[i]) == 0)
	    return i;
    }
    return -1;
}

double recall(char key[])
{
    int address;
    if ((address = lookup(key)) == -1) {
	if (nextentry < MEMSIZE) {
	    memcpy(symbol[nextentry++], key, strlen(key) + 1);
	    return 0;
	} else {
	    fprintf(stderr, "memory room space exceeded... exiting\n");
	    exit(-5);
	}
    }
    return memory[address];
}

double store(double val, char key[])
{
    int address;
    if ((address = lookup(key)) == -1) {
	if (nextentry < MEMSIZE) {
	    memcpy(symbol[address = nextentry++], key, strlen(key) + 1);
	} else {
	    fprintf(stderr, "memory room space exceeded... exiting\n");
	    exit(-5);
	}
    }
    return memory[address] = val;
}

void neg(void)
{
    stack[sp] *= -1;
}

void add(double val)
{
    stack[sp] += val;
}

void sub(double val)
{
    stack[sp] -= val;
}

void mul(double val)
{
    stack[sp] *= val;
}

void divide(double val)
{
    stack[sp] /= val;
}

/** Topdown recursive parser
 * 
 * requires an LL(1) normalized grammar:
 * 
 * mybc -> E <enter>
 * E -> ['-'] T {['+'|'-'] T}
 * T -> F {['*'|'/'] F}
 * F -> NUM | ID ['=' E] | '('E')'
 */

void E(void)
{
    int negate = 0, oplus;
    if (negate = (lookahead == '-'))
	match('-');
    T(); 
    {
	/** negate operation */
	if (negate)
	    neg();
    }
    while (lookahead == '+' || lookahead == '-') {
	match(oplus = lookahead);
	T();
	{
	    /** add/subtract operation */
	    if (oplus == '+')
		add(pop());
	    else
		sub(pop());
	}
    }
}

void T(void)
{
    F();
    while (lookahead == '*' || lookahead == '/') {
	int otimes = lookahead;
	match(lookahead);
	F();
	{
	    /** multiply/division operation */
	    if (otimes == '*')
		mul(pop());
	    else
		divide(pop());
	}
    }
}

void F(void)
{
    char varname[32];
    switch (lookahead) {
    case NUM:
	{
	    /** push value to top of stack */
	    push(lexval);
	}
	match(NUM);
	break;

    case ID:
	strcpy(varname, lexeme);
	match(ID);
	if (lookahead == '=') {
	    match('=');
	    E();
	    {	/** stack operation */
		push(store(pop(), varname));
	    }
	} else {
	    push(recall(varname));
	}
	break;

    default:
	match('(');
	E();
	match(')');
    }
}

void mybc(void)
{
    E();
    match('\n'); 
    {   /** display result */
	printf("%g\n", pop());
    }
}